/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.formserver.viewmodel;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.bizentity.commonstructure.BeCommonStructureUtil;
import com.inspur.edp.caf.cef.schema.structure.CommonStructure;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.util.CommonModelExtension;
import com.inspur.edp.formserver.viewmodel.collection.VMActionCollection;
import com.inspur.edp.formserver.viewmodel.collection.ValueHelpConfigCollection;
import com.inspur.edp.formserver.viewmodel.common.TemplateVoInfo;
import com.inspur.edp.formserver.viewmodel.common.VMAuthConfig;
import com.inspur.edp.formserver.viewmodel.common.ViewModelMapping;
import com.inspur.edp.formserver.viewmodel.dataextendinfo.VoDataExtendInfo;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.exception.VoModelErrorCodes;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelDeserializer;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelSerializer;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Predicate;

/**
 * The Definition Of View Model Metamodel
 *
 * @ClassName: GspViewModel
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
@JsonDeserialize(using = ViewModelDeserializer.class)
@JsonSerialize(using = ViewModelSerializer.class)
public class GspViewModel extends GspCommonModel implements IMetadataContent, Cloneable {
    ///#region 属性

    @Getter
    @Setter
    private VMAuthConfig authConfig;//运行时仅解析型支持此选项, 生成型未支持
    /**
     * 启用标准日期时间格式
     * <see cref="string"/>
     */
    private Boolean enableStdTimeFormat = true;

    public Boolean getEnableStdTimeFormat() {
        return enableStdTimeFormat;
    }

    public void setEnableStdTimeFormat(Boolean enableStdTimeFormat) {
        this.enableStdTimeFormat = enableStdTimeFormat;
    }

    /**
     * 描述
     * <see cref="string"/>
     */
    private String privateDescription;

    public final String getDescription() {
        return privateDescription;
    }

    public final void setDescription(String value) {
        privateDescription = value;
    }

    /**
     * 模型映射：VM可以通过映射规则映射到BE或者其他数据源上
     * <see cref="ViewModelMapping"/>
     */
    private ViewModelMapping privateMapping;

    public final ViewModelMapping getMapping() {

        return privateMapping;
    }

    public final void setMapping(ViewModelMapping value) {
        privateMapping = value;
    }

    /**
     * 根节点
     * <see cref="GspViewObject"/>
     */
    public GspViewObject getMainObject() {
        return (GspViewObject) super.getMainObject();
    }

    void setMainObject(GspViewObject value) {
        super.setMainObject(value);
    }

    /**
     * 获取扩展类型,总是返回为"视图对象"类型
     * <see cref="string"/>
     */
    @Override
    public String getExtendType() {
        return "GspViewModel";
    }


    /**
     * 值帮助配置集合
     */
    private ValueHelpConfigCollection valueHelpConfigs = new ValueHelpConfigCollection();

    /**
     * 值帮助配置集合
     * <see cref="ValueHelpConfigCollection"/>
     */
    public ValueHelpConfigCollection getValueHelpConfigs() {
        return this.valueHelpConfigs;
    }

    public void setValueHelpConfigs(ValueHelpConfigCollection value) {
        this.valueHelpConfigs = value;
    }

    /**
     * 操作集合
     */
    private VMActionCollection actions;

    /**
     * 操作集合
     * <see cref="VMActionCollection"/>
     */
    public final VMActionCollection getActions() {
        if (actions == null) {
            actions = new VMActionCollection();
        }

        return actions;
    }

    public void setActions(VMActionCollection value) {
        this.actions = value;
    }

    private java.util.HashMap<String, String> extendProperties;

    /**
     * 表单拓展节点
     */
    public final java.util.HashMap<String, String> getExtendProperties() {
        if (extendProperties == null) {
            extendProperties = new java.util.HashMap<String, String>();
        }
        return extendProperties;
    }

    public void setExtendProperties(java.util.HashMap<String, String> value) {
        this.extendProperties = value;
    }

    private VoDataExtendInfo dataExtendInfo;

    /**
     * 数据逻辑扩展
     */
    public final VoDataExtendInfo getDataExtendInfo() {
        if (dataExtendInfo == null) {
            dataExtendInfo = new VoDataExtendInfo();
        }
        return dataExtendInfo;
    }

    public void setDataExtendInfo(VoDataExtendInfo value) {
        this.dataExtendInfo = value;
    }

    private TemplateVoInfo templateVoInfo;

    /**
     * 模板VO信息
     */
    public final TemplateVoInfo getTemplateVoInfo() {
        if (templateVoInfo == null) {
            templateVoInfo = new TemplateVoInfo();
        }
        return templateVoInfo;
    }

    public void setTemplateVoInfo(TemplateVoInfo value) {
        this.templateVoInfo = value;
    }

    private boolean autoConvertMessage;

    public boolean getAutoConvertMessage() {
        return autoConvertMessage;
    }

    public void setAutoConvertMessage(boolean value) {
        autoConvertMessage = value;
    }
    ///#endregion

    private String source;

    public String getSource() {
        return source;
    }

    public void setSource(String value) {
        this.source = value;
    }


    private boolean isGenFilterConvertor = true;

    public boolean getIsGenFilterConvertor() {
        return this.isGenFilterConvertor;
    }

    public void setIsGenFilterConvertor(boolean value) {
        this.isGenFilterConvertor = value;
    }

    /**
     * 重载Equals方法
     *
     * @param obj 要比较的对象
     * @return <see cref="bool"/>
     * 如果当前对象等于 other 参数，则为 true；否则为 false。
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj.equals(this)) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }

        return equals((GspViewModel) obj);
    }

    /**
     * 当前对象是否等于同一类型的另一个对象。
     *
     * @param vo 与此对象进行比较的对象。
     * @return 如果当前对象等于 other 参数，则为 true；否则为 false。
     */
    protected boolean equals(GspViewModel vo) {
        if (vo == null) {
            return false;
        }
        //&& this.DevLevelCode == other.DevLevelCode
        //&& this.ForwardMappingID == other.ForwardMappingID
        if (getID() == vo.getID() && getCode() == vo.getCode() && getName() == vo.getName() && getDescription().equals(vo.getDescription()) && getActions().equals(vo.getActions()) && vo.getMapping().equals(getMapping()) && getMainObject().equals(vo.getMainObject()))
        //&& this.SrcDevLevelCode == other.SrcDevLevelCode)
        {
            return true;
        }


        return false;
    }

    /**
     * Serves as a hash function for a particular type.
     *
     * @return A hash code for the current <see cref="T:System.Object" />.
     * <filterpriority>2</filterpriority>
     */
    @Override
    public int hashCode() {
        {
            int hashCode = (getMainObject() != null ? getMainObject().hashCode() : 0);
            hashCode = (hashCode * 397) ^ (getValueHelpConfigs() != null ? getValueHelpConfigs().hashCode() : 0);
            hashCode = (hashCode * 397) ^ (getDescription() != null ? getDescription().hashCode() : 0);
            hashCode = (hashCode * 397) ^ (getMapping() != null ? getMapping().hashCode() : 0);
            hashCode = (hashCode * 397) ^ (actions != null ? actions.hashCode() : 0);
            hashCode = (hashCode * 397) ^ (getMainObject() != null ? getMainObject().hashCode() : 0);
            return hashCode;
        }
    }

    /**
     * 克隆
     *
     * @return <see cref="object"/>
     */

    public final GspViewModel clone() {
        GspCommonModel tempVar = super.clone();

        GspViewModel vo = (GspViewModel) ((tempVar instanceof GspViewModel) ? tempVar : null);
        if (vo == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1053, null);
        }
        if (getMainObject() != null) {
            Object tempVar2 = getMainObject().clone();
            vo.setMainObject((GspViewObject) ((tempVar2 instanceof GspViewObject) ? tempVar2 : null));
            ArrayList<IGspCommonObject> objList = vo.getAllObjectList();
            if (objList != null && objList.size() > 0) {
                for (IGspCommonObject obj : objList) {
                    obj.setBelongModel(vo);
                    obj.setBelongModelID(vo.getID());
                }
            }
        }
        if (getMapping() != null) {
            Object tempVar2 = getMapping().clone();
            vo.setMapping((ViewModelMapping) ((tempVar2 instanceof ViewModelMapping) ? tempVar2 : null));
        }
        if (getValueHelpConfigs() != null) {
            Object valueHelpConfigs = getValueHelpConfigs().clone();
            vo.setValueHelpConfigs((ValueHelpConfigCollection) ((valueHelpConfigs instanceof ValueHelpConfigCollection) ? valueHelpConfigs : null));
        }
        return vo;
    }


    /**
     * 重载ToString方法
     *
     * @return <see cref="string"/>
     */
    @Override
    public String toString() {
        return String.format("ID:%1$s,Code:%2$s,Name:%3$s,RootNode:%4$s", getID(), getCode(), getName(), getMainObject().getCode());
    }

    ///#endregion

    ///#region 获取节点

    /**
     * 查找指定的VM节点
     * <p>
     * //	 @param viewObjectCode 节点编号
     *
     * @return <see cref="GspViewObject"/>
     */
    public final GspViewObject getNode(String nodeCode) {
        return getNode(pre -> pre.getCode().equals(nodeCode));
    }

    public final GspViewObject getNode(Predicate<GspViewObject> predicate) {
        ArrayList<GspViewObject> result = getAllNodes(predicate);
        if (result.size() > 0) {
            return result.get(0);
        }
        return null;
    }


    /**
     * 查询符合条件的节点
     * <p>
     * //	 @param predict
     *
     * @return <see cref="List{T}"/>
     * <see cref="GspViewObject"/>
     */


    public ArrayList<GspViewObject> getAllNodes(Predicate<GspViewObject> predicate) {
        ArrayList<IGspCommonObject> objectLists = CommonModelExtension.getLevelOrderedNodes(this);
        ArrayList<GspViewObject> result = new ArrayList();
        for (IGspCommonObject item : objectLists) {
            if (predicate.test((GspViewObject) item)) {
                result.add((GspViewObject) item);
            }
        }
        return result;
    }


    /**
     * 查询当前VM所有节点的字典
     * 其中Key是节点Code
     *
     * @return <see cref="Dictionary{TKey, TValue}"/>
     * <see cref="string"/>
     * <see cref="GspViewObject"/>
     */
    public final java.util.HashMap<String, GspViewObject> getNodesDic() {
//		return GetNodes(null).ToDictionary(item => item.Code, item => item);
        HashMap toDic = new HashMap();
        for (IGspCommonObject item : getAllObjectList()) {
            toDic.put(item.getCode(), item);

        }
//		return GetNodes(null).ToDictionary(item => item.Code, item => item);
        return toDic;

    }

    ///#endregion

    ///#region 联动-弃用
    /**
     * 与业务实体建立连接
     * <p>
     * //	 @param bizEntity
     *
     * @return <see cref="GspViewModel"/>
     */


    ///#region manager
    private static final String ItemNameTemplate = "I%1$sManager";

    public final String getMgrInterfaceName() {
        return String.format(ItemNameTemplate, getCode());
    }

    public final String getChangesetClassName() {
        return String.format("%1$s%2$s", getCode(), "ViewModelChange");
    }


    public final String getDefaultValueClassName() {
        return String.format("%1$s%2$s", getCode(), "DefaultValue");
    }
    ///#endregion
    ///#endregion

    // region EntityObject.GetRefStructures
    @Override
    protected List<CommonStructure> getCommonModelRefStructures() {
        List<IGspCommonField> fields = new ArrayList<>();
        for (IGspCommonField field : getAllElementList(false)) {
            fields.add(field);
        }
        return BeCommonStructureUtil.getInstance().getElementsRefStructures(fields);
    }

    public GspCommonModel getNewInstance() {
        ObjectMapper mapper = getMapper();
        try {
            String json = mapper.writeValueAsString(this);
            GspViewModel viewModel = mapper.readValue(json, GspViewModel.class);
            return viewModel;
        } catch (JsonProcessingException e) {
            throw new ViewModelException(e);
        }
    }

    private ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(IGspCommonModel.class, new ViewModelSerializer());
        module.addDeserializer(IGspCommonModel.class, new ViewModelDeserializer());
        mapper.registerModule(module);
        return mapper;
    }
    // endregion
}
